#include "Editor.h"
#include "EditorModelSubsystem.h"
#include "EditorViewModelSubsystem.h"
#include "EditorViewSubsystem.h"
#include "Framework/SubsystemManager.h"
#include "File/FileUtils.h"
#include "Serialize/JsonSerializer.h"
#include "Output/Console.h"
#include "Framework/Application.h"
#include "Path/Paths.h"
#include "Theme/EditorTheme.h" 
#include "Asset/AssetSubsystem.h"
#include "Reflection/NativeStruct.h"

static REditor* GEditorSubsystem = nullptr;

void REditor::Initialize()
{
    GetManager()->MakeSureInitialized<RAssetSubsystem>();

    GEditorSubsystem = this;

    InitSetting();

    //make sure the editor state folder exists
    SPath EditorStateFolder= SPaths::GetExecutablePath().Parent() / U"Data";
    if(!EditorStateFolder.Exists())
    {
        SFileUtils::CreateDirectory(EditorStateFolder);
    }

    //register editor state package
    SAssetPackage EditorStatePackage;
    EditorStatePackage.Name=U"EditorState";
    EditorStatePackage.Path=EditorStateFolder.ToString();
    RAssetSubsystem::Get()->AddPackage(EditorStatePackage);
}

void REditor::Deinitialize()
{
    SaveSetting();


    if(ViewSubsystemManager)
    {
        ViewSubsystemManager->DeinitializeSubsystems();
    }

    if(ViewModelSubsystemManager)
    {
        ViewModelSubsystemManager->DeinitializeSubsystems();
    }

    if(ModelSubsystemManager)
    {
        ModelSubsystemManager->DeinitializeSubsystems();
    }

    ModelSubsystemManager=nullptr;
    ViewModelSubsystemManager=nullptr;
    ViewSubsystemManager=nullptr;

    
    GEditorSubsystem = nullptr;
}

REditor *REditor::Get()
{
    return GEditorSubsystem;
}

REditor::FEditorOpenResult REditor::Open()
{
    FEditorOpenResult Result;
    Result.bEmpty=true;

    CurrentTheme=NewObject<REditorTheme>(this);



    ModelSubsystemManager=RAssetSubsystem::Get()->LoadAsset(
        SAssetPath(RSubsystemManager::StaticClass(),U"EditorState",U"./",U"EditorState"));
    if(!ModelSubsystemManager)
    {
        //没有找到序列化的数据，创建一个新的
        ModelSubsystemManager=NewObject<RSubsystemManager>(this);
        ModelSubsystemManager->InitializeSubsystems(REditorModelSubsystem::StaticClass(),ModelSubsystemManager.Get());
    }
    else
    {
        //使用反序列化的数据
        Result.bEmpty=false;
    }

    if(!ViewModelSubsystemManager)
    {
        ViewModelSubsystemManager=NewObject<RSubsystemManager>(this);
    }
    ViewModelSubsystemManager->InitializeSubsystems(REditorViewModelSubsystem::StaticClass(),this);

    if(!ViewSubsystemManager)
    {
        ViewSubsystemManager=NewObject<RSubsystemManager>(this);
    }
    ViewSubsystemManager->InitializeSubsystems(REditorViewSubsystem::StaticClass(),this);

    return Result;
}

void REditor::Exit()
{
    SaveEditorState();
    RApplication::GetApplication()->Exit();
}

void REditor::InitSetting()
{
    //detect if the setting file exists
    //if not, create a new one
    //if exists, load it

    SPath SettingFilePath=GetSettingFilePath();
    if (SettingFilePath.Exists())
    {
        //load the setting file
        CString FileContent=SFileUtils::ReadToString(SettingFilePath);
        auto JsonNode=CJsonUtils::Parse(FileContent);

        if(!JsonNode)
        {
            //json is illegal, just crash
            WH::PrintLine(U"Editor setting file is illegal, please delete it and restart the editor");
            RApplication::GetApplication()->Exit();
            return;
        }

        CJsonDeserializer Deserializer;
        Deserializer.DeserializeFromJson(&CurrentSetting,SEditorSetting::StaticStruct(),JsonNode);
    }
    else
    {
        //create a new setting file
        SaveSetting();
    }

}

void REditor::SaveEditorState()
{
#if SAVE_EDITOR_STATE
    RAssetSubsystem::Get()->AsyncSaveAsset(
        SAssetPath(ModelSubsystemManager->GetClass(),U"EditorState",U"./",U"EditorState")
            ,ModelSubsystemManager
            ,nullptr
            ,nullptr
            ,nullptr
            ,nullptr
            ,true
            );
#endif
}

void REditor::SaveSetting()
{
    //create json object
    CString JsonString;
    {
        CJsonSerializer Serializer;
        auto Json=Serializer.SerializeToJson(&CurrentSetting,SEditorSetting::StaticStruct());
        JsonString=CJsonUtils::ToString(Json);
    }

    SFileUtils::SaveTo(JsonString,GetSettingFilePath());
}

void REditor::AddHistoryProjectInfo(const SProjectPathInfo &InProjectInfo)
{
    //remove the old one if exists
    CurrentSetting.HistoryProjectInfos.Remove(InProjectInfo);

    //add to the first
    CurrentSetting.HistoryProjectInfos.Insert(0,InProjectInfo);

    SaveSetting();
}

SPath REditor::GetSettingFilePath()
{
    return SPaths::GetExecutablePath().Parent()/U"EditorSetting.json";
}
